
#ifndef _NEBULA_SDK__SERVICEAGENT_H_
#define _NEBULA_SDK__SERVICEAGENT_H_

#include "Utility/ErrorCode.h"

namespace nebula { namespace sdk {

class ITask;
class IDoneTaskQueue;
class ITodoTaskQueue;
class ITaskMeta;
class IService;

class IRequest
{
public:
	virtual ~IRequest() {};
	virtual const char* GetParameter     (const char* key) = 0;
	virtual const char* GetResourceName  ()                = 0;
	virtual unsigned    GetParameterCount()                = 0;
	virtual const char* GetKeyAt         (unsigned)        = 0;
	virtual const char* GetParameterAt   (unsigned)        = 0;
};

typedef ITask*   (*TaskAllocator)     (IService*);
typedef NEBULA_ERROR_CODE (*QuerySlotHandler)  (IService*, IRequest*, ITask**);
typedef NEBULA_ERROR_CODE (*DeleteSlotHandler) (IService*, IRequest*);
typedef NEBULA_ERROR_CODE (*UpdateSlotHandler) (IService*, IRequest*, ITask*, ITask**);

enum ServiceState
{
	UN_CONFIGURED = 0,
	CONFIGURING,
	WORKING,
	ABOUT_TO_PAUSING,
	PAUSING,
	ABOUT_TO_RETIRING,
	RETIRING,
	RETIRED,
	ERROR,
	BORNING, // A service is being created
};


class IServiceAgent
{
public:
	virtual ~IServiceAgent() {};
	virtual ServiceState  GetServiceState() = 0;

	//the slot-name is indeed part of the url illustrated as follow:
	// http://host:port/service-name/slot-name?parameters
	// the slot-name should only contain letters, digits, hyphen(-) and underline(_)

	//Register a URL for pushing task into the service
	virtual NEBULA_ERROR_CODE  RegisterPushSlot(const char* name, TaskAllocator alloc, ITodoTaskQueue** queue) = 0;
	
	//Register a URL for popping handled task from the service
	virtual NEBULA_ERROR_CODE  RegisterPopSlot (const char* name, IDoneTaskQueue** queue) = 0;
	
	//Register a URL for querying data from service
	virtual NEBULA_ERROR_CODE  RegisterQuerySlot (const char* name, QuerySlotHandler  handler) = 0;

	//Register a URL for deleting data from service
	virtual NEBULA_ERROR_CODE  RegisterDeleteSlot(const char* name, DeleteSlotHandler handler) = 0;

	//Register a URL for updating data to service and return data as well
	// Note: the name of this type of slot cannot be duplicated with the name of a PushSlot
	// this is because these two type of slots are indeed using the same HTTP verb -- POST 
	virtual NEBULA_ERROR_CODE  RegisterUpdateSlot(const char* name, TaskAllocator alloc, UpdateSlotHandler handler) = 0;

	//Call this API when the service starts configuring itself
	virtual NEBULA_ERROR_CODE  ServiceConfiguring() = 0;

	//Call this API when the service finishes configuring itself
	virtual NEBULA_ERROR_CODE  ServiceConfigured() = 0;

	//Call this API when the service meet some unrecoverable error and has to
	// stop and close
	virtual NEBULA_ERROR_CODE  ServiceError() = 0;

	//Call this API to tell framework that the service needs some specific
	// configurations, separate them by white space
	virtual NEBULA_ERROR_CODE  NeedConfig(const char* configurations) = 0;

	//Get the sum of the size of all the todo queues
	virtual unsigned long      GetTodoQueueSize() = 0;

	//Get the sum of the doing-count of all the todo queues
	virtual unsigned long      GetTodoQueueDoingCount() = 0;

	//Get the sum of the size of all the done queues
	virtual unsigned long      GetDoneQueueSize() = 0;

	//Get the sum of the traffic (the amount of tasks which have been fetched
	// via GetTask during the just past 60 seconds) of all the todo queues
	virtual unsigned long      GetTodoQueueTraffic() = 0;

	//Get the sum of the traffic (the amount of tasks which have been
	// transferred during the just past 60 seconds) of all the done queues
	virtual unsigned long      GetDoneQueueTraffic() = 0;
};

}}

#endif // _NEBULA_SDK__SERVICEAGENT_H_

